K6 测试工具
k6 是什么?
k6 是用 Go 语言编写的一种高性能的负载测试工具。具有下面几个特点。
- K6 嵌入了 JavaScript 运行时,可以使用 JavaScript ES2015/ES6 来编写脚本。
- 强大的 CLI 工具。
- 使用 Checks 和 Thresholds 可以更加轻松的做面向目标的自动化的负载测试。
配置环境
Debian/Ubuntu
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69
echo "deb https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list
sudo apt-get update
sudo apt-get install k6
如果使用 Docker 安装
docker pull grafana/k6
其它安装方式看 官网
如何使用 K6
创建一个 single-request.js 文件
import http from 'k6/http';
import { sleep } from 'k6';
export default function () {
http.get('https://test.k6.io');
sleep(1);
}
运行这个用例:
# 直接使用
k6 run single-request.js
# 使用 docker,这个 - 是 docker 用来接受标准输入的参数,后面那个 < 表示通过管道把 single-request.js 传入进去
docker run -i grafana/k6 run - <single-request.js
# 或者增加点压测,vus 表示虚拟用户数量,duration 表示持续时间
# 这个 vus 实际上是并行的 while (true) 循环
k6 run --vus 10 --duration 30s single-request.js
脚本至少必须包含一个 default function
。这个函数定义了 VUs 的入口点,类似于许多其他语言中的 main 函数
注意,这个 default function
和 main 函数还是有区别的,它会在上面提到的 while (true)
循环重复的执行,但是其它地方的代码只会被执行一次
整个结构如下:
使用 options
上面设置虚拟用户和持续时间是通过命令来指定的,但是每次都需要用户自己指定参数太麻烦了,所以这时可以使用 options 直接指定到脚本上面
import http from 'k6/http';
import { sleep } from 'k6';
export const options = {
vus: 10,
duration: '30s',
};
export default function () {
http.get('http://test.k6.io');
sleep(1);
}
这样直接运行就行了
k6 run script.js
可以加一个 stages 用来模拟瞬时高峰的情况,例如将负载测试配置为在一天的大部分时间内保持60个用户,并在运行的高峰时间内增加到100个用户,然后再减少到正常负载。具体参考官网的 Load testing
export const options = {
stages: [
{ duration: '5m', target: 60 }, // simulate ramp-up of traffic from 1 to 60 users over 5 minutes.
{ duration: '10m', target: 60 }, // stay at 60 users for 10 minutes
{ duration: '3m', target: 100 }, // ramp-up to 100 users over 3 minutes (peak hour starts)
{ duration: '2m', target: 100 }, // stay at 100 users for short amount of time (peak hour)
{ duration: '3m', target: 60 }, // ramp-down to 60 users over 3 minutes (peak hour ends)
{ duration: '10m', target: 60 }, // continue at 60 for additional 10 minutes
{ duration: '5m', target: 0 }, // ramp-down to 0 users
],
thresholds: {
http_req_duration: ['p(99)<1500'], // 99% of requests must complete below 1.5s
},
};
断言 Checks
一个简单的 HTTP 断言
import { check } from 'k6';
import http from 'k6/http';
export default function () {
const res = http.get('http://test.k6.io/');
check(res, {
'is status 200': (r) => r.status === 200,
'body size is 11,105 bytes': (r) => r.body.length == 11105,
'verify homepage text': (r) =>
r.body.includes('Collection of simple web-pages suitable for load testing'),
});
}
细节参考官网 Checks
期望 Thresholds
上面的期望是针对单个请求的,如果希望宏观的检查可以使用 Thresholds
import http from 'k6/http';
export const options = {
thresholds: {
http_req_failed: ['rate<0.01'], // http errors should be less than 1%
http_req_duration: ['p(95)<200'], // 95% of requests should be below 200ms
},
};
export default function () {
http.get('https://test-api.k6.io/public/crocodiles/1/');
}
HTTP 请求
具体使用参考官网 HTTP Requests
import http from 'k6/http';
export let options = {
vus: 100, // 指定要同时运行的虚拟用户数量
duration: '10s', // 指定测试运行的总持续时间
};
// default 默认函数
export default function () {
// 标头
let params = { headers: { 'Content-Type': 'application/json' } };
var res=http.get("https://test.k6.io",params)
}
gRPC 请求
具体使用参考官网 k6/net/grpc
import grpc from 'k6/net/grpc';
import { check, sleep } from 'k6';
const client = new grpc.Client();
client.load(['definitions'], 'hello.proto');
export default () => {
client.connect('grpcb.in:9001', {
// plaintext: false
});
const data = { greeting: 'Bert' };
const response = client.invoke('hello.HelloService/SayHello', data);
check(response, {
'status is OK': (r) => r && r.status === grpc.StatusOK,
});
console.log(JSON.stringify(response.message));
client.close();
sleep(1);
};
这个加载 proto 可以直接通过读取 json 的方式加载配置
{
"protoPaths": [
"../../",
"../../proto/ext"
],
"protoFiles": [
"activity.proto",
"order.proto"
]
}
然后读取时:
export const globalConfig = JSON.parse(open("k6.cfg.json"));
export const grpcClient = new grpc.Client();
grpcClient.load(globalConfig['protoPaths'], ...globalConfig['protoFiles']);
Mock 数据环境
一般需要在执行某个测试前初始化一些数据,这时可以使用自带的客户端
参考 Load Testing SQL Databases with k6
需要先安装这个 xk6-sql
# Install xk6:
go install go.k6.io/xk6/cmd/xk6@latest
# Build the binary:
xk6 build master \
--with github.com/grafana/xk6-sql
编写脚本
// script.js
import sql from 'k6/x/sql';
const db = sql.open("sqlite3", "./test.db");
export function setup() {
db.exec(`CREATE TABLE IF NOT EXISTS keyvalues (
id integer PRIMARY KEY AUTOINCREMENT,
key varchar NOT NULL,
value varchar);`);
}
export function teardown() {
db.close();
}
export default function () {
db.exec("INSERT INTO keyvalues (key, value) VALUES('plugin-name', 'k6-plugin-sql');");
let results = sql.query(db, "SELECT * FROM keyvalues;");
for (const row of results) {
console.log(`key: ${row.key}, value: ${row.value}`);
}
}